# Copyright (c) 2012-4 Aaron Sun <hisycg@gmail.com>. All rights reserved.
# This program is free software; you can redistribute it and/or
# modify it under the same terms as Perl itself.

#!/usr/bin/perl
use warnings;
use strict;
use IO::Socket;
use threads;
use threads::shared;
use Data::Dumper;

$|++;
print "$$ Server started\n";

our @clients_fno : shared;
@clients_fno = ();
our @clients_info: shared;

sub init_start{
  my $server = new IO::Socket::INET(
      Timeout   => 7200,
      Proto     => "tcp",
      LocalPort => 55555,
      Reuse     => 1,
      Listen    => 3
  );
  my $client_number = -1;

  while (1) {
      my $client;

      do {
          $client = $server->accept;
      } until ( defined($client) );

      my $peerhost = $client->peerhost();
      print "accepted a client $peerhost, id = ", ++$client_number, "\n";
      my $fileno = fileno $client;
      push (@clients_fno, $fileno);
      my $thr = threads->new( \&handle_client, $client, $fileno, $peerhost )->detach();
  }
}

sub help{
  my $fh=shift;
  print $fh <<EOF;


******************************
#help  list help information
#users list current users 
******************************

EOF
}

sub handle_cmd{
  my ($fn,$cmd)=@_;
  open my $fh, ">&=$fn" or warn $! and die;
  if($cmd eq "help"){
    help($fh);
  }elsif ($cmd eq "users"){
#     print $fh Dumper($clients_info),"\n";
    print $fh join("\n",@clients_info),"\n";
  }
  else{
    print $fh "command #$cmd not found!\n";
  }
}

sub get_client_info{
  my $txt_from_client=shift;
  my $client_info;
  if($txt_from_client =~ m/^#CLIENTINFO#USER:(.*?),HOST:(.*?)$/){
    ($client_info->{user},$client_info->{host})=($1,$2);
  }
  return $client_info;
}

sub handle_client {
  my ($client_ref,$client_fileno,$client_address) = @_;
  my $client_info;
  if($client_ref->connected){
    print $client_ref "$client_address-> Welcome to server\ntype #help for help\n";  
    while(<$client_ref>){
      my $txt_from_client=$_;
#       print "$client_address->$txt_from_client\n";
#       print "clients file number-> @clients_fno\n";
      if ($txt_from_client =~ m/^#CLIENTINFO#(.*)/){
        $client_info=get_client_info($txt_from_client);
        print "USER:$client_info->{user},HOST:$client_info->{host}\n";
        push(@clients_info,"$client_fileno;$client_info->{user};$client_info->{host};$client_address");
      }
      elsif ($txt_from_client =~ m/^#(\S+)/){
        my $cmd_txt=$1;
        handle_cmd($client_fileno,$1) ;
      }else{
        foreach my $fn (@clients_fno) { 
            open my $fh, ">&=$fn" or warn $! and die;
            print $fh  sprintf("%-10s%-23s: %s",$client_info->{user},"$client_info->{host}/$client_address",
                               $txt_from_client );
        }
      }
    }
  }

  #close filehandle before detached thread dies out
  close( $client_ref);
  #remove multi-echo-clients from echo list
  @clients_fno = grep {$_ !~ $client_fileno} @clients_fno;

}
sub main {
  init_start;
}

&main;